package jdtprototype;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.exceptions.models.EolEnumerationValueNotFoundException;
import org.eclipse.epsilon.eol.exceptions.models.EolModelElementTypeNotFoundException;
import org.eclipse.epsilon.eol.exceptions.models.EolModelLoadingException;
import org.eclipse.epsilon.eol.exceptions.models.EolNotInstantiableModelElementTypeException;
import org.eclipse.epsilon.eol.execute.introspection.IPropertyGetter;
import org.eclipse.epsilon.eol.execute.introspection.IPropertySetter;
import org.eclipse.epsilon.eol.models.Model;
import org.eclipse.epsilon.eol.parse.Eol_EolParserRules.returnStatement_return;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.swt.events.TypedEvent;

public class JdtModel extends Model {

	protected ArrayList<IJavaProject> javaProjectList = new ArrayList<IJavaProject>();
	protected ArrayList <IPackageFragment> packageList = new ArrayList<IPackageFragment>();
	protected ArrayList<TypeDeclaration> typeDecList = new ArrayList<TypeDeclaration>();
	protected ArrayList<MethodDeclaration> methodDecList = new ArrayList<MethodDeclaration>();
	protected List<String> supportedTypes = Arrays.asList("JavaProject","package", "class","method","name");

	@Override
	public void load() throws EolModelLoadingException {
		System.out.println("calling load()");
		IWorkspace workspace = ResourcesPlugin.getWorkspace();
		IWorkspaceRoot root = workspace.getRoot();	
		//get all projects in the workspace
		IProject[] projects = root.getProjects();

		//container for MethodDeclration elements
		List <MethodDeclaration> methodDeclarations = new ArrayList<MethodDeclaration>();
		try {
			//retrieves IJavaProject elements
			javaProjectList.addAll(Arrays.asList(JdtManipulator.getIJavaProjects(projects)));
			for(IJavaProject javaProject : javaProjectList){
				//retrieves IPackageFragment elements
				ArrayList <IPackageFragment>  packages = new ArrayList<IPackageFragment>(Arrays.asList(JdtManipulator.getIPackageFragments(javaProject, true)));
				packageList.addAll(packages);
				for(IPackageFragment packageFragment : packages){
					//retrieves TypeDeclaration elements
					ArrayList <TypeDeclaration> types = new ArrayList<TypeDeclaration>(JdtManipulator.getTypeDeclaration(packageFragment)); 
					typeDecList.addAll(types);
					for(TypeDeclaration type : types){
						//retrieves MethodDeclaration elements
						ArrayList <MethodDeclaration> methods = new ArrayList<MethodDeclaration>(Arrays.asList(type.getMethods()));
						methodDecList.addAll(methods);
					}
				}
			}
		} catch (CoreException e) {

			e.printStackTrace();
		}
		
//		// create a JdtManipulator
//		JdtManipulator jdtManipulator = new JdtManipulator();
//		
//		for(IProject project : projects){
//			JavaProject javaProject = new JavaProject(project);
//			List<Package> packagesList = new ArrayList<Package>();
//			//package		
//			try {
//				// determine if it is a java project
//				if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
//					IPackageFragment [] packages= jdtManipulator.getIPackageFragments(project,true);
//					for(IPackageFragment packageFragment : packages){
//						Package newPackage = new Package(packageFragment);
//						List <Class> classList = new ArrayList<Class>();
//						CompilationUnit [] units = jdtManipulator.getCompilationUnits(packageFragment);
//						for(CompilationUnit unit : units){
//							TypeDeclaration [] type = jdtManipulator.getTypeDeclaration(unit);
//							//only choose the first element, should add a loop here
//							Class newClass = new Class(type[0]);
//							List <Method> methodList = new ArrayList<Method>();
//							MethodDeclaration [] methods = jdtManipulator.getMethodDeclaration(unit);
//							for(MethodDeclaration method : methods){
//								if(method.getModifiers()==0){//if the modifier is "public"
//									Method newMethod = new Method(method);
//									methodList.add(newMethod);//add a method to the list
//								}
//							}
//							newClass.getMethods().addAll(methodList);// add to method list to the class element
//							classList.add(newClass);
//						}
//						newPackage.getClasses().addAll(classList);
//						packagesList.add(newPackage);
//					}
//					javaProject.getPackages().addAll(packagesList);
//					javaProjectList.add(javaProject);
//				}
//			} catch (CoreException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//		}

	}

	@Override
	public Object getEnumerationValue(String enumeration, String label)
			throws EolEnumerationValueNotFoundException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Collection<?> allContents() {
		return javaProjectList;
	}

	@Override
	public Collection<?> getAllOfType(String type)
			throws EolModelElementTypeNotFoundException {
		try {
			load();
		} catch (EolModelLoadingException e) {

			e.printStackTrace();
		}
		if (type.equals("JavaProject")) {

//			for(TypeDeclaration type1 : typeDecList){
//				System.out.println(type1);
//			}
			
//			IWorkspace workspace = ResourcesPlugin.getWorkspace();
//			IWorkspaceRoot root = workspace.getRoot();		
//			// Get all projects in the workspace
//			IProject[] projects = root.getProjects();
			return javaProjectList;
		
//			 List list = new ArrayList<Object>();
//			 list.add("test");
//			 return list;
		}
		
		if (type.equals("package")){
			return packageList;
		}
		
		if (type.equals("class")){
			return typeDecList;
		}
		
		if (type.equals("method")){
			
			return methodDecList;
		}
		
		return null;
	}

	@Override
	public Collection<?> getAllOfKind(String type)
			throws EolModelElementTypeNotFoundException {
		return getAllOfType(type);
	}

	@Override
	public String getTypeNameOf(Object instance) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object createInstance(String type)
			throws EolModelElementTypeNotFoundException,
			EolNotInstantiableModelElementTypeException {
		if (type.equals("JavaProject")){
			JdtElement element = new JavaProject();
		//	javaProjectList.add(element);
			return element;
		}
		return null;
	}

	@Override
	public Object getElementById(String id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getElementId(Object instance) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setElementId(Object instance, String newId) {
		// TODO Auto-generated method stub

	}

	@Override
	public void deleteElement(Object instance) throws EolRuntimeException {
		javaProjectList.remove(instance);
	}

	@Override
	public boolean owns(Object instance) {
		if (instance instanceof TypeDeclaration) {
			for (TypeDeclaration typeDeclaration : typeDecList){
				//compare the String format representation of the object against the object stored in the model
				if((typeDeclaration.toString()).equals(((TypeDeclaration)instance).toString()))
					return true;
			}
//			System.out.println("instance passed from the property getter: "
//					+ ((TypeDeclaration) instance).resolveBinding());
//			System.out.println("instance owned by the model:"
//					+ typeDecList.get(0).resolveBinding());
//			System.out.println("compare the two instances above: "
//					+ ((typeDecList.get(0).toString()).equals(((TypeDeclaration) instance).toString())));
//			String x = new String("1");
//			System.out.println("x="+System.identityHashCode(x));
//			String y = new String("1");
//			System.out.println("y="+System.identityHashCode(y));
//			System.out.println(x.equals(y));
			
//			System.out.println("instance passed from the property getter: "
//
//			+ System.identityHashCode(((IPackageFragment) instance)));
//
//			System.out.println("instance owned by the model:"
//
//			+ System.identityHashCode(packageList.get(0)));
//
//			System.out.println("compare the two instances above: "
//
//			+ (packageList.get(0).equals((IPackageFragment) instance)));
			return false;
		}
		
		if (instance instanceof MethodDeclaration) {
			for (MethodDeclaration methodDeclaration : methodDecList){
				if((methodDeclaration.toString()).equals(((MethodDeclaration)instance).toString()))
					return true;
			}
			return false;
		}
		return javaProjectList.contains(instance) ||
				packageList.contains(instance)/*||
				typeDecList .contains(instance) ||
				methodDecList.contains(instance)*/;
	}

	@Override
	public boolean isInstantiable(String type){
		return true;
	}

	@Override
	public boolean hasType(String type) {
		return supportedTypes.contains(type);
	}

	@Override
	public boolean store(String location) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean store() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public IPropertySetter getPropertySetter() {
		return new JdtPropertySetter();
	}

	@Override
	public IPropertyGetter getPropertyGetter() {
		return new JdtPropertyGetter();
	}
	
//	public ArrayList<IJavaProject> getContents() {
//		return javaProjectList;
//	}
//
//	public void addContents(List<IJavaProject> javaProjectList) {
//		this.javaProjectList.addAll(javaProjectList);
//	}

}
